home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / tpa2_a.arc / MICROMTR.PAS < prev    next >
Pascal/Delphi Source File  |  1991-04-28  |  8KB  |  272 lines

  1. Uses CRT;
  2. {═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
  3. { Usage:  MicroMtr           (From Editor, just Run)                 }
  4. {═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
  5.  
  6. {- This demonstration illustrates the use of Assemble in place of    }
  7. {- Inline to create (Assembly) Inline Directive/MACROs.  The Macros  }
  8. {- StartMicroMeter and StopMicroMeter are used to examine code       }
  9. {- length and execution speed of the section of Pascal or Assembly   }
  10. {- code placed between them.  Precision is sufficient to measure     }
  11. {- down to a single assembly language instruction, however be        }
  12. {- forewarned: the actual in-place execution speed will depend on a  }
  13. {- number of complicated factors, including Prefetch Queue status    }
  14. {- and Byte/Word alignment.  For this reason, differences of 10      }
  15. {- clock cycles (about 3 timer counts) should not be considered      }
  16. {- significant.  For further explanation please see Byron Sheppard,  }
  17. {- "High-Performance Software Analysis on the IBM PC", BYTE Magazine }
  18. {- January 1987, p157.                                               }
  19.  
  20. {-    StartMicroMeter and StopMicroMeter calls cannot be nested     -}
  21.  
  22. {-    MAKE SURE START AND STOP 'MACROS' ARE OF EVEN BYTE LENGTH     -}
  23. {-    THEY SHOULD THEN GIVE AN ACCURATE COUNT FOR IN-PLACE CODE     -}
  24.  
  25.  
  26. {════════════════ Global Variables used by MicroMeter ═══════════════}
  27. VAR
  28.   CodeOverHead : WORD;
  29.   AverageCount, CountOverHead,
  30.   AverageCycles,CycleOverHead : LongInt;
  31.   LoopLoc, Count, Counter, TimerSumLo, TimerSumHi, CodeCount : WORD;
  32.   TimerSum: LongInt Absolute TimerSumLo;
  33.  
  34. {═════════════════════════ StartMicroMeter ══════════════════════════}
  35. { MACRO to start timer and REPEATEDly execute subsequent code.  Use  }
  36. {  MicroMeterInit(1) to examine sections of a working program.       }
  37. {═════════════════════════ StartMicroMeter ══════════════════════════}
  38. PROCEDURE StartMicroMeter;
  39. ASSEMBLE {- Assembly Inline Directive -}
  40. ; Start Code
  41.   Nop   ; Pad to even byte length
  42.   Mov Ax,Count
  43.   Mov Counter,Ax
  44.   Xor Ax,Ax
  45.   Mov TimerSumLo,Ax
  46.   Mov TimerSumHi,Ax
  47.   Jmp Short PushLoopLC
  48. PopLoopLoc:
  49.   Pop LoopLoc
  50.   Jmp Short TimerLoop
  51. PushLoopLC:
  52.   Call PopLoopLoc
  53. TimerLoop:
  54. ;- Initialize timer, counter 0
  55.   Mov Al,$34  ;counter 0, LSB then MSB, mode 2, binary
  56.   Out $43,Al  ;mode register
  57.   Xor Ax,Ax
  58.   Out $40,Al  ;Set LSB
  59.   Out $40,Al  ;Then MSB
  60. END Assemble; {- StartMicroMeter -}
  61.  
  62.  
  63. {══════════════════════════ StopMicroMeter ══════════════════════════}
  64. { MACRO to stop timer and REPEATEDly loop back to last Start.  Use   }
  65. {  MicroMeterInit(1) to examine sections of a working program.       }
  66. {══════════════════════════ StopMicroMeter ══════════════════════════}
  67. PROCEDURE StopMicroMeter;
  68. ASSEMBLE {- Assembly Inline Directive -}
  69. ; Stop code
  70. ;- read timer, counter 0
  71.   Nop         ;Pad to even byte length
  72.   Mov Al,0
  73.   Out $43,Al  ;mode register
  74.   In Al,$40
  75.   Mov Dl,Al
  76.   In Al,$40
  77.   Mov Dh,Al   ;Dx has 16 bit timer count
  78.   Neg Dx      ; = $10000 - Dx
  79.   Add TimerSumLo,Dx
  80.   IF C Inc TimerSumHi
  81.   Dec Counter
  82.   IF NZ Jmp LoopLoc ;Indirect Jmp to Addr stored during StartMicroMeter
  83. ;Else Finished: Use 4*TimerSum/Count to estimate clock cycles
  84.   Call PopLocCounter
  85. PopLocCounter:
  86.   Pop Ax
  87.   Sub Ax,LoopLoc
  88.   Sub Ax,CodeOverhead
  89.   Mov CodeCount,Ax
  90. END Assemble; {- StopMicroMeter -}
  91.  
  92.  
  93. {══════════════════════════ MicroMeterRead ══════════════════════════}
  94. {  Read accumulated sums from last Start/StopMicroMeter loop.        }
  95. {══════════════════════════ MicroMeterRead ══════════════════════════}
  96. PROCEDURE MicroMeterRead;
  97. BEGIN
  98. AverageCount := Round(TimerSum/Count - CountOverHead);
  99. AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
  100. WRITELN(CodeCount,' bytes code   ',
  101.          'Count:  ',AverageCount,'   Cycles: ',AverageCycles);
  102. END;
  103.  
  104. {════════════════════════════ ReadCount ═════════════════════════════}
  105. { Display String S, Code Length, and Average timer counts from last  }
  106. { StartMicroMeter/StopMicroMeter loop.                               }
  107. {════════════════════════════ ReadCount ═════════════════════════════}
  108. PROCEDURE ReadCount(S:String);
  109. BEGIN
  110. AverageCount:= Round(TimerSum/Count - CountOverHead);
  111. WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
  112.           AverageCount,' Timer Counts');
  113. END;
  114.  
  115. {════════════════════════════ ReadCycles ════════════════════════════}
  116. { Display String S, Code Length, and Average clock cycles from last  }
  117. { StartMicroMeter/StopMicroMeter loop. (assumes 4 cycles/count)      }
  118. {════════════════════════════ ReadCycles ════════════════════════════}
  119. PROCEDURE ReadCycles(S:String);
  120. BEGIN
  121. AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
  122. WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
  123.           AverageCycles,' Clock Cycles');
  124. END;
  125.  
  126.  
  127. {══════════════════════════ MicroMeterInit ══════════════════════════}
  128. { Initialize Global repetition Count and determine overhead due to   }
  129. { StartMicroMeter and StopMicroMeter code                            }
  130. {══════════════════════════ MicroMeterInit ══════════════════════════}
  131. PROCEDURE MicroMeterInit(RepCount:WORD);
  132. BEGIN
  133.   Count := RepCount;  {- Set Global Variable -}
  134.   CodeOverHead := 0;
  135.   CountOverHead := 0;
  136.   CycleOverHead := 0;
  137.   StartMicroMeter;
  138.   StopMicroMeter;
  139.   Write('Initializing:   ');
  140.   MicroMeterRead;     {- Compute averages and display -}
  141.   CodeOverHead := CodeCount;
  142.   CountOverHead := AverageCount;
  143.   CycleOverHead := AverageCycles;
  144. END; {PROCEDURE MicroMeterInit;}
  145.  
  146.  
  147.  
  148.  
  149. {══════════════════════ Demonstrate MicroMeter ══════════════════════}
  150. VAR
  151.   n,Dummy : INTEGER;
  152.  
  153. PROCEDURE MulTest;
  154. BEGIN
  155.   WRITELN('Multiply tests:');
  156.   StartMicroMeter;
  157.   ASSEMBLE
  158.     mov dl,15
  159.     mul dl
  160.   End; {Assemble}
  161.   StopMicroMeter;
  162.   ReadCycles('Mul Instruction');
  163.  
  164.   StartMicroMeter;
  165.   ASSEMBLE
  166.     mov dx,ax
  167.     mov cl,4
  168.     sal al,cl
  169.     sub ax,dx
  170.   End; {Assemble}
  171.   StopMicroMeter;
  172.   ReadCycles('Shift(Cl) and subtract');
  173.  
  174.   StartMicroMeter;
  175.   ASSEMBLE
  176.     mov dx,ax
  177.     sal al,1
  178.     sal al,1
  179.     sal al,1
  180.     sal al,1
  181.     sub ax,dx
  182.   End; {Assemble}
  183.   StopMicroMeter;
  184.   ReadCycles('Repeated Shift(1) and subtract');
  185.  
  186. END; {PROCEDURE MulTest;}
  187.  
  188. PROCEDURE IncTest;
  189. BEGIN
  190.   WRITELN('Increment tests:');
  191.   StartMicroMeter;
  192.   Dummy := Dummy + 1;
  193.   StopMicroMeter;
  194.   ReadCycles('Dummy := Dummy + 1;');
  195.  
  196.   StartMicroMeter;
  197.   Dummy := Succ(Dummy);
  198.   StopMicroMeter;
  199.   ReadCycles('Dummy := Succ(Dummy);');
  200.  
  201.   StartMicroMeter;
  202.   Inc(Dummy);
  203.   StopMicroMeter;
  204.   ReadCycles('Inc(Dummy);');
  205.  
  206.   StartMicroMeter;
  207.   Inc(Dummy);
  208.   StopMicroMeter;
  209.   ReadCycles('Inc(Dummy);');
  210.  
  211.   StartMicroMeter;
  212.   Asm Inc Dummy;
  213.   StopMicroMeter;
  214.   ReadCycles('asm Inc Dummy');
  215.  
  216.   StartMicroMeter;
  217.   Asm Inc Dummy;
  218.   StopMicroMeter;
  219.   ReadCycles('asm Inc Dummy');
  220.  
  221.   StartMicroMeter;
  222.   Inc(Dummy);
  223.   StopMicroMeter;
  224.   ReadCycles('Inc(Dummy);');
  225.  
  226.   StartMicroMeter;
  227.   ASSEMBLE
  228.   Mov Ax,Dummy
  229.   Inc Ax
  230.   Mov Dummy,Ax
  231.   End;
  232.   StopMicroMeter;
  233.   ReadCycles('asm Inc Ax:Dummy');
  234.  
  235. END; {PROCEDURE IncTest;}
  236.  
  237. BEGIN
  238.   MicroMeterInit(1000);
  239.  
  240.   StartMicroMeter;
  241.   Dummy := 0;
  242.   StopMicroMeter;
  243.   ReadCycles('Dummy := 0; ');
  244.  
  245.   StartMicroMeter;
  246.   ASSEMBLE
  247.    Mov Dummy,0
  248.   End;
  249.   StopMicroMeter;
  250.   ReadCycles('Mov Dummy,0  ');
  251.  
  252.   StartMicroMeter;
  253.   ASSEMBLE
  254.    Xor ax,ax
  255.    Mov Dummy,ax
  256.   End;
  257.   StopMicroMeter;
  258.   ReadCycles('Xor Ax,Ax | Mov Dummy,Ax  ');
  259.  
  260.  
  261.   IncTest;
  262.   MulTest;
  263.   MicroMeterInit(100);
  264.   StartMicroMeter;
  265.   {- This is a MICROmeter - overflow beyond count 65535 is not detected -}
  266.   {-  Experiment by increasing the loop limit below to cause overflow   -}
  267.    FOR n := 1 TO 20 DO WRITE('Direct Video Write'#13);
  268.   StopMicroMeter;
  269.   ReadCycles('Direct Video Write');
  270.   MicroMeterRead;
  271. END.
  272.